#include <stdio.h>
#include <string.h>

#include "config.h"
#include "STC32G_Timer.h"
#include "STC32G_GPIO.h"
#include "STC32G_NVIC.h"
#include "STC32G_Exti.h"
#include "STC32G_Delay.h"

#include "app_config.h"
#include "drv_spi_norflash.h"
#include "debug.h"

#if TCFG_DRV_SPI_NORFLASH_SUPPORT


#define NOR_CS   P77     // CS  片选
#define NOR_DI   P76     // DI  数据输入
#define NOR_CLK  P75     // CLK 时钟
#define NOR_DO   P74     // DO  数据输出

#define NOR_WP      P73 // WP 写保护        不使用可接至VCC
#define NOR_HOLD    P74 // HOLD 引脚保持    不使用可接至VCC


static struct norflash_dev_t xdata norflash_dev;
#define __this norflash_dev

/**
 * @brief   获取NorFlash设备句柄
 * @param   无
 * @return  struct norflash_dev_t类型指针
*/
struct norflash_dev_t* NorFlash_Handler(void)
{
    return (struct norflash_dev_t*)&norflash_dev;
} 

/**
 * @brief   NorFlash读字节
 * @param   无
 * @return  读取字节数据
*/
static uint8_t NorFlash_Read(void)
{
    // CLK下升沿DO输出数据
    uint8_t i,dat=0;
    NOR_DO = 1;
    for (i=0; i<8; i++)
    {
        NOR_CLK=1;
        dat<<=1;
        dat |= NOR_DO; 
        NOR_CLK=0;
    }
    return dat;
}

/**
 * @brief   NorFlash写字节
 * @param   dat:写入字节数据
 * @return  无
*/
static void NorFlash_Write(uint8_t dat)
{
    // CLK上升沿DI读入数据
    uint8_t i;
    for (i=0; i<8; i++)
    {
        NOR_CLK=0;
        NOR_DI = (dat&0x80);
        NOR_CLK=1;
        dat <<=1;
    }

    NOR_CLK= 0;
    NOR_DI = 0;
}

/**
 * @brief   NorFlash读写字节（写入1字节数据，同时读取1字节数据）
 * @param   dat:写入字节数据
 * @return  读取字节数据
*/
static uint8_t NorFlash_ReadWrite(uint8_t dat)
{
    // CLK上升沿DI读入数据 
    // CLK下升沿DO输出数据(CLK=0数据变化，CLK=1数据锁存 读取数据)
    uint8_t i,read=0;
    NOR_DO = 1;
    for (i=0; i<8; i++)
    {        
        NOR_CLK = 0;
        NOR_DI = (dat&0x80);
        dat <<= 1;
        NOR_CLK=1;
        read<<=1;
        read |= NOR_DO;
    }
    NOR_CLK=0;
    NOR_DI = 0;
    return read;
}

/**
 * @brief   NorFlash等待准备好信号（BUSY标志位）
 * @param   无
 * @return  0:准备好，1：忙状态
*/
static uint8_t NorFlash_WaitReady(void)
{
    uint8_t tryes;
    uint8_t value=0;
    tryes = 200;
    do {
        NOR_CS = 0;
        NorFlash_Write(NOR_ReadStatusREG1);
        __this.reg.REG1._data = NorFlash_Read();
        NOR_CS = 1;
        delay_ms(5);
    }while(__this.reg.REG1.R.BUSY&&tryes--);

    if (__this.reg.REG1.R.BUSY) {
        return 1;   // 出错
    } else {
        return 0;   // 正常
    }
}

void NorFlash_SendAddress(uint32_t address)
{
    if (0) {    // 4Byte Address Enable
        NorFlash_Write((uint8_t)((address>>24)&0xFF));    
    }
    NorFlash_Write((uint8_t)((address>>16)&0xFF));
    NorFlash_Write((uint8_t)((address>>8)&0xFF));
    NorFlash_Write((uint8_t)(address&0xFF));
}

/**
 * @brief   NorFlash读取状态寄存器
 * @param   无
 * @return  无
*/
void NorFlash_ReadStatus(void)
{
    NOR_CS = 0;
    NorFlash_Write(NOR_ReadStatusREG1);
    __this.reg.REG1._data = NorFlash_Read();
    // __this.SREG1 = NorFlash_Read();
    NOR_CS = 1;

    NOR_CS = 0;
    NorFlash_Write(NOR_ReadStatusREG2);
    __this.reg.REG2._data = NorFlash_Read();
    // __this.SREG2 = NorFlash_Read();
    NOR_CS = 1;

    NOR_CS = 0;
    NorFlash_Write(NOR_ReadStatusREG3);
    __this.reg.REG3._data = NorFlash_Read();
    // __this.SREG3 = NorFlash_Read();
    NOR_CS = 1;

    log_d("REG1:%02X, BUSY:%d, WEL:%d, SRP0:%d\n", __this.reg.REG1._data, __this.reg.REG1.R.BUSY, __this.reg.REG1.R.WEL, __this.reg.REG1.R.SRP0);
    log_d("REG2:%02X\n", __this.reg.REG2._data);
    log_d("REG3:%02X, DRVS:%d\n", __this.reg.REG3._data, __this.reg.REG3.R.DRVS);
}

/**
 * @brief   NorFlash休眠
 * @param   无
 * @return  无
 */
void NorFlash_Sleep(void)
{
    NOR_CS = 0;
    NorFlash_Write(NOR_Powerdown);
    NOR_CS = 1;
}

/**
 * @brief   NorFlash唤醒
 * @param   无
 * @return  无
 */
void NorFlash_Wakeup(void)
{
    NOR_CS = 0;
    NorFlash_Write(NOR_ReleasePowerDown);
    NOR_CS = 1;
}

/**
 * @brief   NorFlash读取JEDEC ID
 * @param   无
 * @return  无
*/
void NorFlash_Read_JEDEC_ID(void)
{
    NOR_CS = 0;
    NorFlash_Write(NOR_JEDEC_ID);

    __this.jedec_id.manufacturer_id = NorFlash_Read();    // Manufacturer ID
    __this.jedec_id.memory_type = NorFlash_Read();    // Memory Type
    __this.jedec_id.capacity = NorFlash_Read();    // Capacity
    NOR_CS = 1;
}

/**
 * @brief   NorFlash读取设备ID
 * @param   无
 * @return  2字节设备ID
*/
uint16_t NorFlash_ReadID(void)
{
    uint16_t device_id=0xFFFF;
    
#if 0
    NOR_CS = 0;
    NorFlash_Write(NOR_ManufactDeviceID);
    // 写入address:0x000000
    NorFlash_Write(0x00);
    NorFlash_Write(0x00);
    NorFlash_Write(0x00);

    // 读取Device ID  2Byte
    device_id = NorFlash_Read();
    // log_d("ID:%X",device_id);
    device_id <<= 8;
    device_id |= NorFlash_Read();    
    NOR_CS = 1;
#else
    NOR_CS = 0;
    NorFlash_ReadWrite(NOR_ManufactDeviceID);
    // 写入address:0x000000
    NorFlash_SendAddress(0x000000);
    // 读取Device ID  2Byte
    device_id = NorFlash_ReadWrite(NOR_DummyByte);
    device_id <<= 8;
    device_id |= NorFlash_ReadWrite(NOR_DummyByte);    
    NOR_CS = 1;
#endif
    return device_id;
}



uint8_t NorFlash_Erase(uint8_t eraser, uint32_t address)
{
    // uint32_t i;
    u8 eraser_cmd;

    // 执行擦除命令前先检查忙状态
    if (NorFlash_WaitReady()) {
        log_d("Erase Wait 1 Error\n");
        return 1;
    }

    switch(eraser)
    {
        case NORFLASH_ERASE_PAGE:
            log_i("NORFLASH_ERASE_PAGE\n");
            address = address / 256 * 256;  // 页对齐，1页=256字节
            eraser_cmd = NOR_PageErase; 
            break;
        case NORFLASH_ERASE_SECTOR:
            log_i("NORFLASH_ERASE_SECTOR\n");
            address = address / 4096 * 4096;    // 扇区对齐，1扇区=4096字节
            eraser_cmd = NOR_SectorErase_4KB;
            break;
        case NORFLASH_ERASE_HALF_BLOCK:
            log_i("NORFLASH_ERASE_HALF_BLOCK\n");
            address = address / 32768 * 32768;  // 半块对齐，半个块=32768字节=32KB
            eraser_cmd = NOR_BlockErase_32KB;
            break;
        case NORFLASH_ERASE_BLOCK:
            log_i("NORFLASH_ERASE_BLOCK\n");
            address = address / 65535 * 65535;  // 块对齐，1个块=65535字节=64KB
            eraser_cmd = NOR_BlockErase_64KB;
            break;
        case NORFLASH_ERASE_ALLCHIP:
            log_i("NORFLASH_ERASE_ALLCHIP\n");
            eraser_cmd = NOR_ChipErase;            
            break;
        default:
            log_e("Erase CMD Error\n");
            return 1;
    }


    // 发送写使能命令
    NOR_CS = 0;
    NorFlash_Write(NOR_WriteEnable);
    NOR_CS = 1;

    // 发送擦除命令
    NOR_CS = 0;
    NorFlash_Write(eraser_cmd);
    if (NOR_ChipErase != eraser_cmd) {
        // 不是擦除全片命令，写入地址
        NorFlash_SendAddress(address);
    }    
    NOR_CS = 1;

    if (NorFlash_WaitReady()) {
        log_d("Erase Wait 2 Error\n");
        return 1;
    }

    return 0;
}


uint8_t NorFlash_ReadBuffer(uint8_t *buffer, uint32_t address, uint32_t len)
{
    uint32_t i;

    NOR_CS = 0;
    NorFlash_Write(NOR_ReadData);
    NorFlash_SendAddress(address);
    for(i=0; i<len; i++)
    {
        buffer[i] = NorFlash_Read();
    }
    NOR_CS = 1;
    return 0;
}

uint8_t NorFlash_WritePage(uint8_t *buffer, uint32_t address, uint32_t len)
{
    uint32_t i;

    NOR_CS = 0;
    NorFlash_Write(NOR_WriteEnable);
    NOR_CS = 1;

    NOR_CS = 0;
    NorFlash_Write(NOR_PageProgram);
    NorFlash_SendAddress(address);
    for(i=0; i<len; i++)
    {
        NorFlash_Write(buffer[i]);
    }
    NOR_CS = 1;
    
    if (NorFlash_WaitReady()) {
        log_d("Write Wait Error\n");
        return 1;
    }

    return 0;
}

uint8_t NorFlash_WriteBuffer(uint8_t *buffer, uint32_t address,  uint32_t len)
{
    uint8_t num_of_page = 0, num_of_single = 0, addr = 0, count = 0, temp = 0;

    addr          = address % NORFLASH_PAGE_SIZE;
    count         = NORFLASH_PAGE_SIZE - addr;
    num_of_page   = len / NORFLASH_PAGE_SIZE;
    num_of_single = len % NORFLASH_PAGE_SIZE;

    /* address is NORFLASH_PAGE_SIZE aligned  */
    if(0 == addr){
        /* len < NORFLASH_PAGE_SIZE */
        if(0 == num_of_page)
            NorFlash_WritePage(buffer,address,len);
        /* len > NORFLASH_PAGE_SIZE */
        else{
            while(num_of_page--){
                NorFlash_WritePage(buffer,address,NORFLASH_PAGE_SIZE);
                address += NORFLASH_PAGE_SIZE;
                buffer += NORFLASH_PAGE_SIZE;
            }
            NorFlash_WritePage(buffer,address,num_of_single);
        }
    }else{
        /* address is not NORFLASH_PAGE_SIZE aligned  */
        if(0 == num_of_page){
            /* (len + address) > NORFLASH_PAGE_SIZE */
            if(num_of_single > count){
                temp = num_of_single - count;
                NorFlash_WritePage(buffer,address,count);
                address += count;
                buffer += count;
                NorFlash_WritePage(buffer,address,temp);
            }else
                NorFlash_WritePage(buffer,address,len);
        }else{
            /* len > NORFLASH_PAGE_SIZE */
            len -= count;
            num_of_page = len / NORFLASH_PAGE_SIZE;
            num_of_single = len % NORFLASH_PAGE_SIZE;

            NorFlash_WritePage(buffer,address, count);
            address += count;
            buffer += count;

            while(num_of_page--){
                NorFlash_WritePage(buffer,address,NORFLASH_PAGE_SIZE);
                address += NORFLASH_PAGE_SIZE;
                buffer += NORFLASH_PAGE_SIZE;
            }

            if(0 != num_of_single)
                NorFlash_WritePage(buffer,address,num_of_single);
        }
    }

    return 0;
}


uint8_t NorFlash_Init(void)
{
    log_d("NorFlash_Init\n");
    
    NOR_WP = 1;
    NOR_HOLD = 1;
    NOR_CS = 1;
    NOR_CLK = 0;
    NOR_DI = 0;
    NOR_DO = 0;

    NorFlash_Read_JEDEC_ID();
    log_d("manufacturer_id:0x%X\n", __this.jedec_id.manufacturer_id);
    log_d("memory_type:0x%X\n", __this.jedec_id.memory_type);
    log_d("capacity:0x%X\n", __this.jedec_id.capacity);

    __this.device_id = NorFlash_ReadID();
    log_d("DeviceID:0x%04X\n", __this.device_id);

#if 0
    __this.page_size = 256;
    __this.sector_size = 16*256;    // 4KB
    __this.sector_count = 16777216/4096;// 扇区个数=总容量/扇区大小
    __this.block_size = 16*16*256;      // 64KB
#endif
		return 0;
}


uint8_t NorFlash_GPIO_Config(void)
{
    // P7_SPEED_LOW(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2);
    P7_SPEED_HIGH(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2);
    P7_PULL_UP_ENABLE(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2);
    P7_DRIVE_MEDIUM(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2);
    // P7_DRIVE_HIGH(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_4|GPIO_Pin_3|GPIO_Pin_2);

    P7_MODE_OUT_PP(GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5|GPIO_Pin_3|GPIO_Pin_2);


    // 配置DI为高阻输入模式
    P7_MODE_IO_PU(GPIO_Pin_4);
    // P7_MODE_IN_HIZ(GPIO_Pin_4);
    P7_DIGIT_IN_ENABLE(GPIO_Pin_4);
    // P7_PULL_UP_ENABLE(GPIO_Pin_4);
    // P7_PULL_UP_DISABLE(GPIO_Pin_4);
		
		return 0;
}

#if 0
#define D_NORFLASH_TEST_ADDR 0x000000 //(0x400000)
void NorFlash_Test(void)
{
    int i=0;
    uint8_t buffer[256*4];

    memset(buffer, 0, sizeof(buffer));


    NorFlash_Erase(NORFLASH_ERASE_SECTOR, D_NORFLASH_TEST_ADDR);
    log_d("Erase Sector\n");

    for(i=0; i<512; i++)
    {
        if (i<256)
            buffer[i] = i;
        else
            buffer[i] = 0x3A;
    }
    NorFlash_WritePage(buffer, D_NORFLASH_TEST_ADDR, 512);
    log_d("Norflash Write\n");


    NorFlash_ReadBuffer(buffer, D_NORFLASH_TEST_ADDR,  512);
    log_d("NorFlash Read:\n");
    for(i=0; i<512; i++)
    {
        log_d("%02x,", buffer[i]);
    }
    log_d("\n");
}
#endif

#endif



